﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonLib {
    public delegate double Operator(double a);

    public class DoubleTester {
        public const double Epsilon = 10e-10;
        public static void Assert(double a, double b) {
            double tmp = a - b;
            System.Diagnostics.Debug.Assert(IsZero(tmp));
        }
        public static bool IsZero(double d) {
            return -Epsilon <= d && d <= Epsilon;
        }
    }

    public struct Int3 {
        public int x, y, z;
        public Int3(int _x, int _y, int _z) {
            this.x = _x;
            this.y = _y;
            this.z = _z;
        }
        public Int3(Vector3c v) {
            this.x = (int)v.x;
            this.y = (int)v.y;
            this.z = (int)v.z;
        }
        public void crop(int vmin, int vmax) {
            x = (x > vmax ? vmax : (x < vmin ? vmin : x));
            y = (y > vmax ? vmax : (y < vmin ? vmin : y));
            z = (z > vmax ? vmax : (z < vmin ? vmin : z));
        }
        public void max(int xmax, int ymax, int zmax) {
            x = (x > xmax ? xmax : x);
            y = (y > ymax ? ymax : y);
            z = (z > zmax ? zmax : z);
        }
        public void min(int xmin, int ymin, int zmin) {
            x = (x < xmin ? xmin : x);
            y = (y < ymin ? ymin : y);
            z = (z < zmin ? zmin : z);
        }
    }

    public struct Vector3c {
        public double x, y, z;

        //public void() {
        //    x = 0;
        //    y = 0;
        //    z = 0;
        //}
        public Vector3c(double _x, double _y, double _z) {
            x = _x;
            y = _y;
            z = _z;
        }

        public void set(double _x, double _y, double _z) {
            x = _x;
            y = _y;
            z = _z;
        }
        public void add(Vector3c v) {
            x += v.x;
            y += v.y;
            z += v.z;
        }
        public void add(double v) {
            x += v;
            y += v;
            z += v;
        }
        public void sub(Vector3c v) {
            x -= v.x;
            y -= v.y;
            z -= v.z;
        }
        public void sub(double v) {
            x -= v;
            y -= v;
            z -= v;
        }
        public void mul(Vector3c v) {
            x *= v.x;
            y *= v.y;
            z *= v.z;
        }
        public void mul(double v) {
            x *= v;
            y *= v;
            z *= v;
        }
        public void div(Vector3c v) {
            x /= v.x;
            y /= v.y;
            z /= v.z;
        }
        public void div(double v) {
            double rv = 1.0 / v;
            x *= rv;
            y *= rv;
            z *= rv;
        }
        public double dot(Vector3c v) {
            return (x * v.x) + (y * v.y) + (z * v.z);
        }
        public void mac(Vector3c u, Vector3c v) {
            x += u.x * v.x;
            y += u.y * v.y;
            z += u.z * v.z;
        }
        public void mac(double u, Vector3c v) {
            x += u * v.x;
            y += u * v.y;
            z += u * v.z;
        }
        // cross product
        //         | i   j   k   |
        // u x v = | u.x u.y u.z |
        //         | v.x v.y v.z |
        public Vector3c cross(Vector3c v) {
            return new Vector3c(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
        }
        public double norm() {
            return Math.Sqrt(x * x + y * y + z * z);
        }
        public void normalize() {
            div(norm());
        }
        public bool Equals(Vector3c v) {
            double e = DoubleTester.Epsilon;
            double dx = x - v.x;
            double dy = y - v.y;
            double dz = z - v.z;
            double d2 = (dx * dx) + (dy * dy) + (dz * dz);
            return d2 <= e;
        }
        public void calc(Operator op) {
            x = op(x);
            y = op(y);
            z = op(z);
        }
    }
}
